package com.ghery.ftp.client;

import com.ghery.ftp.config.FtpConfiguration;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * @author ghery
 * @date 2020/10/28 18:19
 * @desc ftp链接工厂类
 */
public class FtpClientFactory extends BasePooledObjectFactory<FTPClient> {

    private Logger log = LoggerFactory.getLogger(FtpClientFactory.class);

    private FtpConfiguration config;

    public FtpClientFactory(FtpConfiguration config) {
        this.config = config;
    }

    /**
     * 创建FtpClient对象
     */
    @Override
    public FTPClient create() {
        FTPClient ftpClient = new FTPClient();
        try {
            ftpClient.setConnectTimeout(10000);
            ftpClient.connect(config.getIp(), config.getPort());
            int replyCode = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                ftpClient.disconnect();
                log.error("FTPServer refused connection,replyCode:{}", replyCode);
                return null;
            }
            if (!ftpClient.login(config.getUsername(), config.getPassword())) {
                ftpClient.disconnect();
                log.error("ftpClient login failed... username is {}; password: {}", config.getUsername(), config.getPassword());
                return null;
            }
            ftpClient.setSoTimeout(30000);
            ftpClient.setBufferSize(config.getBufferSize());
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.setControlEncoding("UTF-8");
            ftpClient.enterLocalPassiveMode();//被动模式
            return ftpClient;
        } catch (IOException e) {
            log.error("create ftp connection failed...", e);
            return null;
        }
    }

    /**
     * 用PooledObject封装对象放入池中
     */
    @Override
    public PooledObject<FTPClient> wrap(FTPClient ftpClient) {
        return new DefaultPooledObject<>(ftpClient);
    }

    /**
     * 销毁FtpClient对象
     */
    @Override
    public void destroyObject(PooledObject<FTPClient> ftpPooled) {
        if (ftpPooled == null) {
            return;
        }

        FTPClient ftpClient = ftpPooled.getObject();

        try {
            if (ftpClient.isConnected()) {
                ftpClient.logout();
            }
        } catch (IOException io) {
            log.error("ftp client logout failed...{}", io);
        } finally {
            try {
                ftpClient.disconnect();
            } catch (IOException io) {
                log.error("close ftp client failed...{}", io);
            }
        }
    }

    /**
     * 验证FtpClient对象
     */
    @Override
    public boolean validateObject(PooledObject<FTPClient> ftpPooled) {
        try {
            FTPClient ftpClient = ftpPooled.getObject();
            return ftpClient.sendNoOp();
        } catch (IOException e) {
            log.error("Failed to validate client: {}", e);
        }
        return false;
    }

}